﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Server.Protocol
{

    enum ParserType
    {
        UTF8
    }

    class ProtocolParser
    {
        public const int Head = 4;
        public const int Len = 4;

        byte[] _data;
        int _offset;
        int _len;

        readonly Func<byte[], int, int, object> _Decode;
        readonly Func<object, byte[]> _Encode;

        public event Action<object> Complete;

        public static ProtocolParser GetUTF8Parser()
        {
            return new ProtocolParser(ParserType.UTF8);
        }

        public ProtocolParser(ParserType type)
        {
            if (type == ParserType.UTF8)
            {
                _Encode = (obj) =>
                {
                    byte[] content = Encoding.UTF8.GetBytes(obj as string);
                    byte[] data = new byte[content.Length + 4];
                    Array.Copy(BitConverter.GetBytes(content.Length), data, 4);
                    Array.Copy(content, 0, data, 4, content.Length);
                    return data;
                };
                _Decode = (data, offset, count) =>
                {
                    return Encoding.UTF8.GetString(data, offset, count);
                };
            }
        }

        public void Push(byte[] data, int offset, int count)
        {
            if (_data == null)
            {
                if (count < 4)
                    return;

                _len = BitConverter.ToInt32(data, offset);
                _data = new byte[_len];
                _offset = 0;
                offset += 4;
                count -= 4;
            }
            else if (_offset < _len)
            {
                int len = count > _len - _offset ? _len - _offset : count;
                Array.Copy(data, offset, _data, _offset, len);
                _offset += len;
                offset += len;
                count -= len;
            }
            else
            {
                Complete?.Invoke(_Decode?.Invoke(_data, 0, _len));
                _data = null;
            }

            Push(data, offset, count);
        }

        public byte[] Encode(object obj)
        {
            return _Encode?.Invoke(obj);
        }


    }
}
